home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
TARFILE.GZ
/
tarfile
/
ch_4.3
/
xcc
/
circ_geo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
9KB
|
357 lines
/*
* circ_geo.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/*
* CIRC(le)_GEOM(etry)
*
* collection of routines to evaluate geometrical properties
* of circular shapes
*/
#include "xcc.h"
#define SYMM 0
#define ASYMM 1
#define CCC_MODE ASYMM /* mode of center coord computation */
/*
* evaluate slope of linear segment
*/
double
slopev (struct spoint pt1, struct spoint pt2)
{
double m;
double max_slope = 500.0; /* max. poss. slope */
double r1, c1, r2, c2;
r1 = (double) pt1.y;
c1 = (double) pt1.x;
r2 = (double) pt2.y;
c2 = (double) pt2.x;
if (F_TO_INT (r2 - r1) == 0) {
if (F_TO_INT (c2 - c1) == 0)
m = 0.0;
else
m = max_slope;
}
else
m = (c2 - c1) / (r2 - r1);
return (m);
}
/*
* evaluate moments of order 0 (m00) and of order 1 (m10, m01)
*
* note: not very useful for evaluation of center coord, because disks
* are not sampled ``symmetrically'': --> center pos biased
*/
struct spoint
eval_centroid (int *x, int *y, int n)
{
double xi, ximm, yi, yimm;
double m00, m00_sum;
double m10, m10_sum, m01, m01_sum;
struct spoint ctr;
int i;
/*
* compute moments
* (reference: Hu, IRE Trans. Inf. Theory, IT-8, 179-187 (1962) )
* (see also module pmom.c)
*/
m00 = m10 = m01 = 0.0;
for (i = 1; i < n; i++) {
ximm = (double) (*(x + i - 1));
xi = (double) (*(x + i));
yimm = (double) (*(y + i - 1));
yi = (double) (*(y + i));
m00_sum = 0.5 * (yi * ximm - xi * yimm);
m00 += m00_sum;
m10_sum = 0.5 * (xi + ximm) * m00_sum;
m10_sum -= 0.5 * ((yi - yimm) * (xi * xi + xi * ximm + ximm * ximm) / 6.0);
m10 += m10_sum;
m01_sum = 0.5 * (yi + yimm) * m00_sum;
m01_sum += 0.5 * ((xi - ximm) * (yi * yi + yi * yimm + yimm * yimm) / 6.0);
m01 += m01_sum;
}
ctr.y = (short) F_TO_INT (m10 / m00);
ctr.x = (short) F_TO_INT (m01 / m00);
#ifdef DBG_EVAL_CENTROID
printf ("EVAL_CENTROID -- centroid of %3d-vertex polygon:", n);
printf (" (%3d, %3d)\n", ctr.r, ctr.c);
#endif
return (ctr);
}
/*
* estimate center coords of circular shape based on (horizontal)
* disk chord and two line segments by constructing the intersection
* of the respective perpendicular bisectors
*
* symmetric case (CCC_MODE = SYMM):
* construct line segments connecting respective right and left end
* points of disk chord and edge tuple;
* asymmetric case (CCC_MODE = ASYMM):
* construct line segment connecting respective left end points of
* disk chord and edge tuple, as well as line segment connecting
* left end point of disk chord with right end point of edge tuple
* (preferred on basis of error analysis)
*/
double
pbi_ctr (int ir, struct edge_tuple *cetpl, struct triple *cdsk_lchrd)
{
struct spoint eL, eR;
struct spoint cL, cR;
double dcc;
double ecL_r, ecR_r;
/* initialize variables */
cL.y = cR.y = cdsk_lchrd->r;
cL.x = cdsk_lchrd->cl;
cR.x = cdsk_lchrd->cr;
eL.y = eR.y = ir;
eL.x = cetpl->cl;
eR.x = cetpl->cr;
/* dcc = (double)cdsk->ctr.x; */
dcc = 0.5 * (0.5 * (cL.x + cR.x) + 0.5 * (eL.x + eR.x));
/* ctr r-coord derived from left edge points */
ecL_r = 0.5 * (eL.y + cL.y) - (dcc - 0.5 * (eL.x + cL.x)) * slopev (cL, eL);
/* ctr r-coord derived from right edge points */
if (CCC_MODE == SYMM)
ecR_r = 0.5 * (eR.y + cR.y) - (dcc - 0.5 * (eR.x + cR.x)) * slopev (cR, eR);
/* ctr r-coord derived from right eTpl and left dChrd edge points */
if (CCC_MODE == ASYMM)
ecR_r = 0.5 * (eR.y + cL.y) - (dcc - 0.5 * (eR.x + cL.x)) * slopev (cL, eR);
return (0.5 * (ecL_r + ecR_r));
}
/*
* for future use (?) -- to be tested!!
*
* construct estimate of center coords on the basis of osculating circles
* computed from successive triples of vertices
*
* for explicit formula, see e.g.:
* ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 10, probl 10.11
* Comp Sci Press, Rockville, Md, 1982
*/
struct spoint
eval_ctr (struct spoint *v, int n)
{
struct spoint ctr;
struct spoint *pvmm, *pv, *pvpp;
double dmr, dpr, dmc, dpc;
double smr, spr, smc, spc;
double c1, c2, d;
double cr, scr, cc, scc;
long nv;
int i;
scr = scc = 0.0;
nv = 0;
for (i = 0; i < n; i++) { /* form all triples of non-coll vertices */
pv = &v[i];
if (i == 0)
pvmm = &v[n - 1];
else
pvmm = &v[i - 1];
if (i == n - 1)
pvpp = &v[0];
else
pvpp = &v[i + 1];
dmr = pvmm->y - pv->y; /* x1-x2 */
dmc = pvmm->x - pv->x; /* y1-y2 */
dpr = pv->y - pvpp->y; /* x2-x3 */
dpc = pv->x - pvpp->x; /* y2-y3 */
if (fabs (d = (dmr * dpc - dpr * dmc)) < 0.000001) {
d = 0.0;
printf ("EVAL_CTR -- WARNING: vertices collinear\n");
}
else {
smr = pvmm->y + pv->y; /* x1+x2 */
smc = pvmm->x + pv->x; /* y1+y2 */
spr = pv->y + pvpp->y; /* x2+x3 */
spc = pv->x + pvpp->x; /* y2+y3 */
c1 = dmr * smr + dmc * smc;
c2 = dpr + spr + dpc * spc;
/* evaluate sum of ctr coords, to be averaged */
cr = 0.5 * (c1 * dpc - c2 * dmc) / d;
scr += cr;
cc = 0.5 * (c2 * dmr - c1 * dpr) / d;
scc += cc;
nv++;
printf ("EVAL_CTR -- ");
printf ("nv=%ld, cr=%lf, cc=%lf\n", nv, cr, cc);
}
}
ctr.y = (short) F_TO_INT (scr / nv);
ctr.x = (short) F_TO_INT (scc / nv);
#ifdef DBG_EVAL_CTR
printf ("EVAL_CTR -- center of circ, based on %3d-vertex polygon:", n);
printf (" (%3d, %3d)\n", ctr.r, ctr.c);
#endif
return (ctr);
}
/*
* find best circle to fit set of points {(x_i, y_i), 0<=i<n}
* with center position given by centroid: compute radius of inertia
*
* ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 12.6.2, probl 12.5
* Comp Sci Press, Rockville, Md, 1982
*/
int
oeval_rad (struct spoint *v, int n, struct disk *cdsk)
{
double sdrsq, sdcsq;
double r_bar, c_bar;
int i;
r_bar = (double) cdsk->ctr.y;
c_bar = (double) cdsk->ctr.x;
sdrsq = sdcsq = 0.0;
for (i = 0; i < n; i++) {
sdrsq += SQR ((v + i)->y - r_bar);
sdcsq += SQR ((v + i)->x - c_bar);
}
return (F_TO_INT (sqrt ((sdrsq + sdcsq) / n)));
}
/*
* find best circle to fit set of points {(x_i, y_i), 0<=i<n}
* with center position given by centroid: compute radius of inertia
*
* ref: Pavlidis, ``Alg for Graphics and Img Proc'', sect 12.6.2, probl 12.5
* Comp Sci Press, Rockville, Md, 1982
*/
int
eval_rad (struct disk *cdsk)
{
struct spoint *v;
double sdrsq, sdcsq;
double r_bar, c_bar;
int ich, nch;
int iv, nv;
nch = cdsk->nch;
if ((v = (struct spoint *) calloc (2 * (nch + 1), sizeof (struct spoint))) == NULL) {
printf ("\n...mem alloc for array of vertices v failed!!\n");
return (0);
}
/*
* extract vertex coords
*/
for (ich = 0; ich < nch; ich++) {
(v + ich)->y = (v + ((2 * nch - 1) - ich))->y = cdsk->chords[ich].r;
(v + ich)->x = cdsk->chords[ich].cl;
(v + ((2 * nch - 1) - ich))->x = cdsk->chords[ich].cr;
}
r_bar = (double) cdsk->ctr.y;
c_bar = (double) cdsk->ctr.x;
sdrsq = sdcsq = 0.0;
nv = 2 * nch;
for (iv = 0; iv < nv; iv++) {
sdrsq += SQR ((v + iv)->y - r_bar);
sdcsq += SQR ((v + iv)->x - c_bar);
}
free (v);
return (F_TO_INT (sqrt ((sdrsq + sdcsq) / nv)));
}
/*
* generate a new estimate of the best circle for the current set
* of contour points: estimate the center in form of the centroid,
* then compute a (suboptimal) value of the radius in form of the
* radius of inertia
*/
int
oeval_circ (struct disk *cdsk)
{
struct spoint *v;
int ich, nch;
nch = cdsk->nch;
if ((v = (struct spoint *) calloc (2 * (nch + 1), sizeof (struct spoint))) == NULL) {
printf ("\n...mem alloc for array of vertices v failed!!\n");
return (0);
}
/*
* evaluate new centroid position and update entry in disk structure
*/
for (ich = 0; ich < nch; ich++) {
(v + ich)->y = (v + ((2 * nch - 1) - ich))->y = cdsk->chords[ich].r;
(v + ich)->x = cdsk->chords[ich].cl;
(v + ((2 * nch - 1) - ich))->x = cdsk->chords[ich].cr;
}
#ifdef DBG_EVAL_CTR
printf ("EVAL_CIRC -- polygon vertex coords, {(r, c}\n");
for (ich = 0; ich < 2 * nch; ich++)
printf (" (%3d, %3d)\n", (v + ich)->y, (v + ich)->x);
#endif
cdsk->ctr = eval_ctr (v, 2 * nch);
printf ("\n...new estimated center position: (%3d, %3d)\n",
cdsk->ctr.y, cdsk->ctr.x);
/*
* estimate new radius
*/
cdsk->rad = oeval_rad (v, 2 * nch, cdsk);
printf ("...estimated radius: %d\n", cdsk->rad);
free (v);
return (1);
}